console.inspectEnable = true;
const WebApp = require('webapp');
const bodyParser = require("middleware").bodyParser;
const Device = require('device');
const { checkPerm } = require('./common/util');
const facenn = require('facenn');
const imagecodec = require('imagecodec');
const fs = require('fs');
const path = require('path');
const app = WebApp.createApp();
app.use(bodyParser.json());
app.use(WebApp.static('./public'));
const notify = require('notify');

const LIGHT_SCENES = [
	// 灯泡场景
	'relax',
	'night',
	'movies',
	'wakeup',
	'dinner',
	'reading',
];

// device
const { devManager } = require('./data/device_manager');

// lightKV DataBase
const { sceneDB } = require('./data/lkv_db');

// 场景设备对象
let cameraDev = null; // 摄像头设备
let curImageSize = 0;
let lwirDev = null; // 红外设备
let lockDev = null; // 门锁设备
let lightDev = null; // 小米灯设备
let t = 0; // 定时器
let lockStatus = 'OFF';  // 锁的开关状态 ON / OFF
let lwir_camera_lock_light_scene = sceneDB.get('lwir_camera_lock_light');

if (!lwir_camera_lock_light_scene) {
	lwir_camera_lock_light_scene = {
		devids: [],
		settings: {
			faces: []
		}
	}
	updateSceneDB();
}

// socket.io server
const { initSocketIO } = require('./common/socket_server');
const socketIO = initSocketIO(app);
socketIO.on('connection', (socket) => {
	console.info('socket connection')
	socket.on('sync', (cb) => { // 应用socket断线重连
		cb({
			cameraId: cameraDev ? cameraDev.devid : '',
			lockId: lockDev ? lockDev.devid : '',
			lwirId: lwirDev ? lwirDev.devid : '',
			lightId: lightDev ? lightDev.devid : ''
		})
	});
	socket.on('init', () => { // 应用初始化
		init();
	});
	socket.on('init-scene', () => { // 初始化场景
		initScene();
	});
	socket.on('change-scene-devices', (data) => {  // {delete_id: string, add_id: string}; 改变场景设备
		changeSceneDevice(data)
	});
	socket.on('send-device-message', (params) => {  // {devid: string, data: any}; 发送设备控制信息
		const { devid, data } = params;
		devManager.sendDeviceInfo(devid, data).catch((err) => {
			emitError(err || '操作失败！')
		})
	});
	socket.on('delete-member', (name) => { // 删除成员
		try {
			lwir_camera_lock_light_scene.settings.faces = lwir_camera_lock_light_scene.settings.faces.filter((item) => {
				return item.name !== name;
			})
			updateSceneDB();
			emitMembers();
			emitSuccess('删除成员成功！');
		} catch (error) {
			emitError('删除成员失败，请稍后重试！')
		}
	})
})

// 初始化应用前端数据
function init() {
	emitDevices();
	emitMembers();
	initScene();
}

// 初始化场景
async function initScene() {
	if (!lwir_camera_lock_light_scene) {
		lwir_camera_lock_light_scene = {
			devids: [],
			settings: {
				faces: []
			}
		}
		updateSceneDB();
	}
	for (const devid of lwir_camera_lock_light_scene.devids) {
		const dev = devManager.devMap.get(devid);
		if (!dev) {
			continue;
		}
		const type = getDeviceType(dev)
		if (type === 'camera') {
			try {
				await checkPerm(['network', 'ainn']);
			} catch (error) {
				emitError('当前应用需要网络通信和AI权限，请到设置中赋予权限！');
				continue;
			}
		}
		if (!devManager.controllerMap.has(devid)) {
			generateDevController(devid).then(() => {
				setSceneDevice(dev)
				socketIO.emit('join', dev);
			}).catch((err) => {
				setSceneDevice(dev)
				emitError(err);
			})
		} else {
			socketIO.emit('join', dev); // 其他用户进入应用后同步设备状态
		}
	}
}

// 同步设备列表
function emitDevices() {
	socketIO.emit('devices', [...devManager.devMap.values()]);
}

// 同步成员列表
function emitMembers() {
	if (!lwir_camera_lock_light_scene || !lwir_camera_lock_light_scene.settings || !lwir_camera_lock_light_scene.settings.faces) {
		emitError('获取授权人员信息失败，请退出重试！');
	} else {
		const names = getMemberNames();
		socketIO.emit('members', names);
	}
}

// 成功提示
function emitSuccess(msg) {
	socketIO.emit('success', msg);
}

// 错误提示
function emitError(msg) {
	socketIO.emit('error', msg);
}

// 改变场景设备
async function changeSceneDevice(data) {
	const { add_id, delete_id } = data;
	if (delete_id) {
		deleteSceneDev(delete_id); 	// 删除上一个设备
		devManager.deleteController(delete_id);
	}
	// 替换新设备
	if (!add_id) {
		return emitError('设备切换失败！')
	}
	const dev = devManager.devMap.get(add_id);
	// 检测应用权限
	if (dev) {
		const type = getDeviceType(dev);
		if (type === 'camera') {
			try {
				await checkPerm(['network', 'ainn']);
			} catch (error) {
				return emitError('当前应用需要网络通信和AI权限，请到设置中赋予权限！')
			}
		}
		generateDevController(add_id).then(() => {
			lwir_camera_lock_light_scene.devids.push(add_id);
			updateSceneDB();
			setSceneDevice(dev);
			socketIO.emit('join', dev);
		}).catch((err) => {
			emitError(err);
		})
	}
}

// 添加成员信息
const multer = require('middleware').multer;
const upload = multer({ dest: 'uploads/' });
// const upload = multer({ storage: multer.memoryStorage() });
app.post('/upload-file', upload.any(), (req, res) => {
	// 检测用户名是否存在
	const isExistName = lwir_camera_lock_light_scene.settings.faces.find((item) => { return item.name === req.body.name });
	if (isExistName) {
		return res.send({ result: false, message: '当前用户名的用户已存在！' });
	}
	const buffer = fs.readFile(path.join('./', req.files[0].path));
	const features = getFaceFeature(buffer);
	if (!features) {
		return res.send({ result: false, message: '人脸识别出错！' })
	}
	if (!features.length || features.length > 1) {
		return res.send({ result: false, message: '请确保图片中有且仅有单人头像！' });
	}
	// 先检测数据库中是否存在该人脸的信息
	const isExistFace = checkFaceAuthorization(features[0].keys);
	if (isExistFace) {
		return res.send({ result: false, message: '当前人脸信息已经在数据库中存在！' });
	}
	// 将人脸信息key录入数据库中
	lwir_camera_lock_light_scene.settings.faces.push({ name: req.body.name, keys: features[0].keys })
	updateSceneDB();
	res.send({ result: true, message: '人脸录入成功！' });
	emitMembers()
})

devManager.on('join', async (dev) => {
	console.log('devManager join.')
	emitDevices();
	if (lwir_camera_lock_light_scene.devids.includes(dev.devid)) {
		// 说明加入的设备是当前场景设备
		const type = getDeviceType(dev);
		if (type === 'camera') {
			try {
				await checkPerm(['network', 'ainn'])
			} catch (error) {
				return emitError('当前应用需要网络通信和AI权限，请到设置中赋予权限！');
			}
		}
		generateDevController(dev.devid).then(() => {
			setSceneDevice(dev);
			socketIO.emit('join', dev);
		}).catch(() => {
			emitError('应用缺少控制' + dev.alias + '的权限！');
		})

	}
});

devManager.on('lost', (dev) => {
	console.warn('[devManager lost]:', JSON.stringify(dev));
	emitDevices();
	if (dev && isSceneDev(dev.devid)) {
		if (lockDev && lockDev.devid === dev.devid) {
			lockDev = null;
		} else if (cameraDev && cameraDev.devid === dev.devid) {
			cameraDev = null;
		} else if (lwirDev && lwirDev.devid === dev.devid) {
			lwirDev = null;
		} else if (lightDev && lightDev.devid === dev.devid) {
			lightDev = null;
		}
		const type = getDeviceType(dev)
		if (type === 'camera' || type === 'lwir') {
			console.warn('[devManager lost clearInterval].');
			clearInterval(t);
		}
		socketIO.emit('lost', dev);
	}
});

devManager.on('error', (data) => {
	emitError(data)
})

// 构建设备控制对象
function generateDevController(devid) {
	return new Promise((resolve, reject) => {
		const dev = devManager.devMap.get(devid) || {};
		const type = getDeviceType(dev);
		devManager.generateController(devid).then((controller) => {
			controller.on('message', (data) => {
				console.info('message:', data);
				if (type === 'lock') {
					// 门锁
					socketIO.emit('lock', data.data.unlock);
					lockStatus = data.data.unlock;
					if (lockStatus === 'ON' && lightDev && lightDev.devid) {
						const lightController = devManager.controllerMap.get(lightDev.devid);
						if (lightController) {
							lightController.send({
								channel0: true
							}, undefined, 3)
						}
					}
				} else if (type === 'lwir') {
					// 红外感应
					if (data.data.proximity === 'ON' && cameraDev) {
						socketIO.emit('people')
						notify.push('智能猫眼', '检测到有人出现！');
						t = setInterval(() => {
							recogniseCateyeView(devManager.controllerMap.get(cameraDev.devid));
						}, 500);
					} else {
						clearInterval(t);
					}
				} else if (type === 'camera') {
					curImageSize = data.size;
					console.log('image size: ', curImageSize)
				}
			});
			resolve(controller);
		}).catch(() => {
			reject(`应用缺少控制${dev.alias}的权限！`);
		})
	})
}

// 获取猫眼视图进行人脸识别分析开锁
function recogniseCateyeView(controller) {
	if (!controller) {
		return;
	}
	getCateyeData(controller)
		.then((chunk) => {
			// 人脸分析
			const features = getFaceFeature(chunk);
			let isAuthorization = false; // 图片中是否存在授权用户
			if (features && features.length) {
				let scenes = '';
				switch (features[0].emotion) {
					case 'happy':
						scenes = 'relax'
						break;
					case 'sad':
						scenes = 'night'
						break;
					default:
						scenes = 'wakeup'
						break;
				}
				socketIO.emit('emotion', features[0].emotion);
				if (lightDev && lightDev.devid) {
					const lightController = devManager.controllerMap.get(lightDev.devid);
					if (lightController && lockStatus === 'ON') { // 开锁状态期间可以改变色温
						lightController.send({
							scenes
						}, undefined, 3)
					}
				}

				for (const item of features) {
					isAuthorization = checkFaceAuthorization(item.keys);
					if (isAuthorization) {
						break;
					}
				}
			} else {
				socketIO.emit('similarity', 0);
				socketIO.emit('face', { name: '' });
			}
			socketIO.emit('image', chunk.toString('base64'));
			if (isAuthorization && lockStatus === 'OFF') {
				unlock();
			}
		}).catch((err) => {
			console.error(err)
		})
}

// 获取猫眼数据
function getCateyeData(controller) {
	return new Promise((resolve, reject) => {
		const camConnector = new Device.Connector(controller, true);
		let chunks = [];
		// camConnector.on('connect', function () {
		// 	console.info('connect');
		// })
		camConnector.on('data', function (chunk) {
			// console.info('data');
			chunks.push(chunk);
		})
		// camConnector.on('close', function () {
		// 	console.info('close');
		// })
		camConnector.on('error', function (error) {
			chunks = [];
			reject('connector error.')
		})
		camConnector.on('finish', function () {
			console.info('finish', chunks.length, curImageSize);
			if (!curImageSize) {
				return reject('no image size.');
			}
			if (!chunks.length) {
				return reject('no receive image.')
			}
			const chunk = Buffer.concat(chunks);
			console.log('chunk compare: ', chunk.length, curImageSize)
			if (chunk.length === curImageSize) {
				resolve(chunk);
			} else {
				reject('chunk lose.');
			}
		})
		camConnector.on('timeout', function (error) {
			chunks = [];
			reject('connector timeout')
		})
		controller.send({
			cam: 'image',
			connector: camConnector
		}, undefined, 3)
	})
}

// 获取图片上的人脸特征信息
function getFaceFeature(picture) {
	if (!picture) {
		return
	}
	const bitmap = imagecodec.decode(picture, {
		components: imagecodec.COMPONENTS_RGB
	});
	if (!bitmap || !bitmap.buffer) {
		return
	}
	const faces = facenn.detect(bitmap.buffer, {
		width: bitmap.width,
		height: bitmap.height,
		pixelFormat: facenn.PIX_FMT_RGB24
	}, true);
	const faceFeatures = [];
	if (faces.length) {
		let feature;
		faces.map((item) => {
			feature = facenn.feature(bitmap.buffer, {
				width: bitmap.width,
				height: bitmap.height,
				pixelFormat: facenn.PIX_FMT_RGB24
			}, item, {
				live: true,
				emotion: true
			})
			faceFeatures.push(feature);
		})
	}
	return faceFeatures;
}

// 检查人脸是否为授权成员
function checkFaceAuthorization(key) {
	for (const item of lwir_camera_lock_light_scene.settings.faces) {
		const res = facenn.compare(key, item.keys);
		if (res > 0) {
			socketIO.emit('similarity', Number((res * 100).toFixed(1)));
		}
		console.log("compare: ", res)
		if (res > 0.55) {
			socketIO.emit('face', { name: item[0] });
			return true;
		}
	}
	socketIO.emit('face', { name: '' });
	return false;
}

// 开锁
function unlock() {
	devManager.sendDeviceInfo(lockDev.devid, {
		method: 'set',
		unlock: 'ON',
		open_time: 5000
	}).catch(() => {
		emitError('开锁失败，请重试！')
	})
}

// 设置场景设备
function setSceneDevice(dev) {
	const type = getDeviceType(dev);
	if (type === 'camera') {
		cameraDev = dev
	} else if (type === 'lock') {
		lockDev = dev
	} else if (type === 'light') {
		lightDev = dev
	} else {
		lwirDev = dev;
	}
}

// 删除场景设备
function deleteSceneDev(devid) {
	lwir_camera_lock_light_scene.devids = lwir_camera_lock_light_scene.devids.filter((id) => {
		return id !== devid
	})
	updateSceneDB();
}

// 更新猫眼场景数据库
function updateSceneDB() {
	sceneDB.set('lwir_camera_lock_light', lwir_camera_lock_light_scene);
}

// 获取录入的授权人员姓名列表
function getMemberNames() {
	return lwir_camera_lock_light_scene.settings.faces.map((item) => {
		return item.name;
	})
}

// 是否是场景设备
function isSceneDev(devid) {
	return lwir_camera_lock_light_scene.devids.findIndex((id) => (id === devid)) >= 0
}

/**
 * 获取设备类型
 * @param dev 设备信息
 * @returns 设备类型
 */
function getDeviceType(dev) {
	const {
		report: { type, model, vendor, name }
	} = dev;
	if (type === 'device.lock' && model === 'IDLOCK01B') {
		return 'lock';
	} else if (type === 'device.hwjj' && model === 'IDHWJJ01B') {
		return 'lwir';
	} else if (model === 'aqcn02' && name === 'light' && vendor === 'lumi') {
		return 'light';
	} else if (type === 'camera') {
		return 'camera';
	}
}

app.start();
require('iosched').forever();
